package com.example.gateway.config;
import com.example.gateway.cluster.ClusterManager;
import com.example.gateway.custom.CustomReactorNettyRequestUpgradeStrategy;
import com.example.gateway.custom.CustomReactorNettyWebSocketClient;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.config.HttpClientProperties;
import org.springframework.cloud.gateway.filter.WebsocketRoutingFilter;
import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import org.springframework.web.reactive.socket.server.WebSocketService;
import org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService;
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.client.WebsocketClientSpec;
import java.util.List;
import java.util.function.Supplier;

@Configuration
public class GatewayWebsocketConfiguration {

    private final Integer MAX_FRAME_PAYLOAD_LENGTH = 65536;


    @Bean
    public ClusterManager getClusterManager(){
        return new ClusterManager();
    }

    @Bean("customWebSocketService")
    @Primary
    public WebSocketService webSocketService(ClusterManager clusterManager) {
        CustomReactorNettyRequestUpgradeStrategy strategy = new CustomReactorNettyRequestUpgradeStrategy(clusterManager);
        strategy.setMaxFramePayloadLength(MAX_FRAME_PAYLOAD_LENGTH);
        return new HandshakeWebSocketService(strategy);
    }

    @Bean("customWebsocketRoutingFilter")
    @Primary
    public WebsocketRoutingFilter websocketRoutingFilter(WebSocketClient webSocketClient,
                                                         WebSocketService webSocketService, ObjectProvider<List<HttpHeadersFilter>> headersFilters) {

        return new WebsocketRoutingFilter(webSocketClient, webSocketService, headersFilters);
    }

    @Bean("customReactorNettyWebSocketClient")
    @Primary
    public WebSocketClient reactorNettyWebSocketClient(HttpClientProperties properties,
                                                       HttpClient httpClient,ClusterManager clusterManager) {
        Supplier<WebsocketClientSpec.Builder> builderSupplier = () -> {
            WebsocketClientSpec.Builder builder = WebsocketClientSpec.builder()
                    .handlePing(properties.getWebsocket().isProxyPing());
            if (properties.getWebsocket().getMaxFramePayloadLength() != null) {
                builder.maxFramePayloadLength(properties.getWebsocket().getMaxFramePayloadLength());
            }
            return builder;
        };
        return new CustomReactorNettyWebSocketClient(httpClient, builderSupplier,clusterManager);
    }


}
